﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LoadTask
{
	// ------------------------------------------------------------------------------------------
	// 加载队列
	List<Loader> m_loaderPool = new List<Loader>();
	List<Loader> m_loaders = new List<Loader>();
	Queue<Loader> m_loaderQueue = new Queue<Loader>();

	// ------------------------------------------------------------------------------------------
	// 加载进度
	enum FrontLoadFlag
	{
		WAIT_LOAD,
		LOADING,
	}

	FrontLoadFlag m_loadFlag = FrontLoadFlag.LOADING;
	int m_currnetCount;
	int m_totalCount;

	class LoaderWaitList
	{
		public Loader loader;
		public List<LoadManager.LoadedCallback> callbacks;
	}

	Dictionary<string, LoaderWaitList> m_waits = new Dictionary<string, LoaderWaitList>();

	// ------------------------------------------------------------------------------------------
	// 
	class AsyncCallbackInfo
	{
		LoadManager.LoadedCallback onLoaded;
		object data;

		public AsyncCallbackInfo(LoadManager.LoadedCallback l, object d)
		{
			onLoaded = l;
			data = d;
		}

		public void OnDelayCallback()
		{
			if (onLoaded != null) {
				onLoaded (data);
			}
		}
	}

	List<AsyncCallbackInfo> m_asyncCallbackInfos = new List<AsyncCallbackInfo>();

	public LoadTask()
	{
		
	}

	public void Clear ()
	{
		//ClearLoader ();
	}

	public void Update(float dt)
	{
		int index = 0;
		Loader loader = null;

		while (index < m_loaders.Count) {
			loader = m_loaders [index];
			loader.Update (dt);

			if (loader.IsFinish) {
				m_loaders.RemoveAt (index);
				if (!m_loaderQueue.Contains (loader)) {
					m_loaderPool.Add (loader);
				}

				CheckNextTask ();
			} else {
				++index;
			}
		}

		UpdateAsyncCallback ();
	}

	void CheckNextTask(bool start = false)
	{
		if (m_loadFlag != FrontLoadFlag.LOADING) {
			return;
		}

		if (m_loaders.Count > 0) {
			return;
		}

		if (m_loaderQueue.Count > 0) {
			Loader loader = m_loaderQueue.Dequeue ();
			m_loaders.Add (loader);

			if (!loader.IsFinish) {	//因为队列中的loader有可能以为其他同步加载的依赖关系，导致被提早加载了
				loader.Load ();
			}

			++m_currnetCount;
			RefreshLoadProgress (0f);
		} else {
			m_currnetCount = 0;
			m_totalCount = 0;
		}
	}

	public bool CheckImmediateLoad (string fullpath, LoadManager.LoadedCallback onLoaded)
	{
		Loader ldr = CheckWaitLoading (fullpath, onLoaded);
		if (ldr == null) {
			return false;
		}

		//如果是同步加载
		if (ldr.State == Loader.LoaderState.NONE) {
			//如果还没开始加载，则直接加载，这里相当于是提高加载优先级，因此在处理异步的队列的时候要加上检查是否finish
			ldr.ChangeToSync ();
			m_loaders.Add (ldr);
			ldr.Load ();
		}
		return true;
	}

	public void AddAsyncCallback(LoadManager.LoadedCallback onLoaded, object data)
	{
		if (onLoaded == null) {
			return;
		}

		m_asyncCallbackInfos.Add (new AsyncCallbackInfo (onLoaded, data));
	}

	void UpdateAsyncCallback()
	{
		for (int i = 0; i < m_asyncCallbackInfos.Count; ++i) {
			m_asyncCallbackInfos [i].OnDelayCallback ();
		}

		m_asyncCallbackInfos.Clear ();
	}

	// ------------------------------------------------------------------------------------------
	// 等待加载
	Loader CheckWaitLoading(string path, LoadManager.LoadedCallback onLoaded)
	{
		LoaderWaitList waitLst;
		if (!m_waits.TryGetValue (path, out waitLst)) {
			m_waits.Add (path, new LoaderWaitList ());

			return null;
		} else {
			List<LoadManager.LoadedCallback> datas = waitLst.callbacks;
			if (datas == null) {
				datas = new List<LoadManager.LoadedCallback> ();
				waitLst.callbacks = datas;
			}

			datas.Add (onLoaded);
			return waitLst.loader;
		}
	}

	//设置loader
	void SetWaitLoader(string path, Loader loader)
	{
		LoaderWaitList waitLst;
		if (m_waits.TryGetValue (path, out waitLst)) {
			waitLst.loader = loader;
		} else {
			Debuger.LogError ("SetWaitLoader:{0}, have no wait list ....", path);
		}
	}

	public void WaitLoadingFinish(string path, object data)
	{
		LoaderWaitList waitLst;
		if (!m_waits.TryGetValue (path, out waitLst)) {
			return;
		}

		List<LoadManager.LoadedCallback> datas = waitLst.callbacks;
		if (datas != null) {
			for (int i = 0; i < datas.Count; ++i) {
				LoadManager.LoadedCallback onLoaded = datas [i];
				if (onLoaded != null) {
					onLoaded (data);
				}
			}

			datas.Clear ();
		}

		m_waits.Remove (path);
	}

	public int GetWaitLoadingCount(string path)
	{
		if (!m_waits.ContainsKey (path)) {
			return 0;
		}

		LoaderWaitList datas = m_waits [path];
		if (datas == null || datas.callbacks == null) {
			return 0;
		}

		return datas.callbacks.Count;
	}

	// ------------------------------------------------------------------------------------------
	// 加载器
	Loader GetLoader(Loader.LoaderType type)
	{
		Loader loader = null;
		for (int i = 0; i < m_loaderPool.Count; ++i) {
			loader = m_loaderPool [i];
			if (loader.Type == type) {
				m_loaderPool.RemoveAt (i);
				break;
			}

			loader = null;
		}

		if (loader == null) {
			switch (type) {
			case Loader.LoaderType.STREAM:
				loader = new StreamLoader ();
				break;

			case Loader.LoaderType.ASSET:
				loader = new AssetLoader ();
				break;

			case Loader.LoaderType.SCENE:
				loader = new SceneLoader ();
				break;

			case Loader.LoaderType.RESOURCE:
				loader = new ResourceLoader ();
				break;

			case Loader.LoaderType.BUNDLE:
				loader = new BundleLoader ();
				break;

			case Loader.LoaderType.BUNDLEASSET:
				loader = new BundleAssetLoader ();
				break;
			}
		}

		return loader;
	}

	void ClearLoader()
	{
		Loader loader = null;
		for (int i = 0; i < m_loaders.Count; ++i) {
			loader = m_loaders [i];
			loader.Stop ();
		}

		m_loaderPool.AddRange (m_loaders);
		m_loaderPool.AddRange (m_loaderQueue);

		m_loaders.Clear ();
		m_loaderQueue.Clear ();
	}

	Loader AddLoadTask(Loader.LoaderType type, string path, object param, Loader.LoadedHandle onLoaded, bool async)
	{
		Loader loader = GetLoader (type);
		loader.Init (path, param, OnLoadProgress, onLoaded, async);

		if (!async) {
			m_loaders.Add (loader);
			loader.Load ();
		} else {
			//Debuger.Log ("Add Task: {0}", path);
			m_loaderQueue.Enqueue (loader);
			if (m_totalCount != 0) {
				++m_totalCount;
			}
		}

		if (m_loaders.Count == 0) {
			CheckNextTask ();
		}

		return loader;
	}

	public void AddLoadTask(Loader.LoaderType type, string path, object param, LoadManager.LoadedCallback onLoaded, bool async)
	{
		if (type != Loader.LoaderType.SCENE && type != Loader.LoaderType.BUNDLE) {
			if (CheckWaitLoading (path, onLoaded) != null) {
				return;
			}
		}

		Loader ldr = AddLoadTask (type, path, param, (loader, data) => {
			if (onLoaded != null) {
				onLoaded (data);
			}

			if (type != Loader.LoaderType.SCENE && type != Loader.LoaderType.BUNDLE) {
				WaitLoadingFinish (path, data);
			}
		}, async);
		//只有异步加载才有所谓等待列表
		if (async && type != Loader.LoaderType.SCENE) {
			SetWaitLoader (path, ldr);
		}
	}

	// ------------------------------------------------------------------------------------------
	// 前台加载
	public void BeginFrontLoad()
	{
		m_loadFlag = FrontLoadFlag.WAIT_LOAD;
	}

	public void StartFrontLoad()
	{
		if (m_loadFlag != FrontLoadFlag.WAIT_LOAD) {
			return;
		}

		m_loadFlag = FrontLoadFlag.LOADING;

		m_currnetCount = 0;
		m_totalCount = m_loaderQueue.Count;

		CheckNextTask (true);
	}

	void RefreshLoadProgress(float addRate)
	{
		float rate = addRate;
		int count = m_totalCount;
		int index = Mathf.Max (0, m_currnetCount - 1);

		if (count == 0) {
			index = 0;
			count = 1;
		} else {
			rate = (index + addRate) / m_totalCount;
		}

		//Debuger.Log("Load Progress: {0}/{1} {2}%", index, count, Mathf.FloorToInt(rate * 100));
		LuaHelper.CallLuaFunction (LuaEventDefine.LOAD_PROGRESS, index, count, rate);
	}

	void OnLoadProgress(Loader loader, float rate)
	{
		if (!loader.IsAsync) {
			return;
		}

		RefreshLoadProgress (rate);
	}
}
